/*
 (Only read this file if you're interested in the implementation
  of the chat filtering system, or documentation of procs).

 A class for cleaning up messages.
 */

MessageCleaner
	var

		// Maximum message length. -1 when there is none.
		message_length_max		= 450

		// Should I add a link to allow users to see a long message (in the browser)?
		has_long_message_link	= TRUE

		// The form of the link in the end of a long message.
		has_long_message_link_form = "\[...]"

		// Should I encode HTML or macros in messages?
		_has_html_encode		= TRUE

		// Should I filter whitespace from messages? (encodes HTML if used)
		has_filter_whitespace	= TRUE

		// Should I format an all-capitals message (such as "HELLO WORLD")?
		has_remove_capitals	= FALSE

		// A list of words to filter, if there are any. Associative: words are associated with their replacement.
		list/filtered_words


	/* Constructor for MessageCleaner.

		[Arg]						[Effect]
		length_max					Maximum message length. -1 if there is none.
		filtered_words				A list of words filtered by this MessageCleaner.
		message_link				Should I add a link to allow users to see a long message (in the browser)?
		encode_html					Should I encode HTML or macros in messages?
		remove_capitals				Should I format messages wholly in capitals?
		filter_whitespace			Should I filter whitespace (\n, \t, three consequentive spaces) and the such?

	*/
	New (max_length = 450, filtered_words[], remove_capitals = FALSE, message_link = TRUE, encode_html = TRUE, filter_whitespace = TRUE)
		setMessageLengthMax(max_length)
		setFilteredWords(filtered_words)
		setHasRemoveCapitals(remove_capitals)
		setHasLongMessageLink(message_link)
		setHasHTMLEncode(encode_html)
		setHasFilterWhitespace(filter_whitespace)

	proc
		/* Sets/gets the maximum message length. (number) */
		setMessageLengthMax(num)	message_length_max = num
		getMessageLengthMax()		return message_length_max

		/* Sets and gets the filtered words list. (list) */
		setFilteredWords(list/lst)	filtered_words = lst
		getFilteredWords()			return filtered_words

		/* Adds and removes from the filtered words list.
			(takes string, returns true if the operation succeeded) */
		addFilteredWord(word, replace)
			var/list/filtered = getFilteredWords()
			if (!filtered)
				filtered = new /list
				setFilteredWords(filtered)
			if (lowertext(word) in filtered) return FALSE
			filtered[word] = (replace || "\[censored]")
			return TRUE
		removeFilteredWord(word)
			var/list/filtered = getFilteredWords()
			if (!(lowertext(word) in filtered)) return FALSE
			filtered.Remove(word)
			return TRUE

		/* Sets/gets whether to encode HTML or macros in a message. (boolean) */
		setHasHTMLEncode(bool)		_has_html_encode = bool
		getHasHTMLEncode()			return _has_html_encode

		/* Sets/gets whether to format all-capital messages. */
		setHasRemoveCapitals(bool)	has_remove_capitals = bool
		getHasRemoveCapitals()		return has_remove_capitals

		/* Sets/gets whether to filter whitespace. */
		setHasFilterWhitespace(bool)has_filter_whitespace = bool
		getHasFilterWhitespace()	return has_filter_whitespace

		/* Sets/gets whether to add a link to continue message in the end
			one above the maximum allowed length. (boolean) */
		setHasLongMessageLink(bool)	has_long_message_link = bool
		getHasLongMessageLink()		return has_long_message_link

		/* Returns a link that, when clicked upon, will show a message. */
		getLongMessageLink(message)
			return "\[...]"

		/* Cleans a given message and returns it. */
		CleanMessage(message)
			var/length = length(message)

			if (getHasHTMLEncode())
				message = html_encode(message)

				if (getHasFilterWhitespace())
					message = FilterWhitespace(message)

			if (getHasRemoveCapitals())
				message = FilterCapitals(message)

			if (length(getFilteredWords()) > 0)
				message = FilterWords(message)

			if (length > getMessageLengthMax())
				message = FilterLength(message)

			return message

		/* Filters message length. */
		FilterLength(message)
			if (getMessageLengthMax() == 0) message = ""
			var/remainder = copytext(message, getMessageLengthMax())
			message = copytext(message, 1, getMessageLengthMax())
			if (getHasLongMessageLink()) message = "[message] [getLongMessageLink(remainder)]"
			return message

		/* Filters whitespace from message (\n, \t, "   "). */
		FilterWhitespace(message)
			if (!getHasHTMLEncode())
				message = html_encode(message)
			message = _replace_text(message, "\t", "")
			message = _replace_text(message, "\n", "")
			message = _replace_text(message, "   ", "")
			return message

		/* Formats messages wholly in capitals. */
		FilterCapitals(message)
			return (message == uppertext(message) ? lowertext(message) : message)

		/* Filters words from message. */
		FilterWords(message)
			var/list/filtered = getFilteredWords()
			for (var/word in filtered)
				message = _replace_text(message, word, filtered[word])
			return message




		// Private:
		// Ubiquitous replace text proc:
		_replace_text(haystack, needle, replace, case_sensitive = FALSE)
			var/needle_length	= length(needle)
			var/replace_length	= length(replace)
			var/position		= (case_sensitive ?	findtextEx(haystack, needle) : \
													findtext(haystack, needle))
			while (position)
				haystack	= copytext(haystack, 1, position) + replace + \
							copytext(haystack, position+needle_length)
				position	= (case_sensitive ?	findtext(haystack, needle,position+replace_length) : \
												findtextEx(haystack, needle,position+replace_length))
			return haystack
